%{
#include <cstdlib>
#include <cstdio>
#include <string>
#include <iostream>
#include <map>
#include <vector>

/* Membros:
   Flávio Coutinho da Costa 			DRE: 107362797
   Luiz Felipe da Costa Pericolo Barbosa 	DRE: 108056098
   Marco Elisio Oliveira Jardim 		DRE: 107390596
*/

using namespace std;

int yylex();
int yyparse();

void yyerror( const char* st );

#define YYSTYPE Atributos

struct Tipo {
  string base;
  int dim1, 
      dim2;

  Tipo(): base(""), dim1(0), dim2(0) {}
  Tipo( string base, int dim1 = 0, int dim2 = 0 ): 
    base(base), dim1(dim1), dim2(dim2) {}
};

string toString( const string& nome, const Tipo& t );

struct Atributos {
  string c,  // Codigo 
         v;  // Valor
  Tipo   t;  // Tipo
};

struct Funcao {
  Tipo retorno;
  vector< Tipo > params;
  vector< string > nomeParams;
};

void geraCodigoOperador( Atributos& ss,
                         string opr,
                         const Atributos& s1,
                         const Atributos& s3 );

void geraCodigoArray1( Atributos& ss, 
                       const Atributos& s1,
                       const Atributos& s3 ); 

void geraCodigoArray2( Atributos& ss, 
                       const Atributos& s1,
                       const Atributos& s3,
                       const Atributos& s5 ); 

void geraAtribuicao( Atributos& ss, 
                     const Atributos& s1,
                     const Atributos& s3  );

void geraAtribuicaoArray1( Atributos& ss, 
                           const Atributos& s1,
                           const Atributos& s3,
                           const Atributos& s6 );

void geraAtribuicaoArray2( Atributos& ss, 
                           const Atributos& s1,
                           const Atributos& s3,
                           const Atributos& s5,
                           const Atributos& s8 );

string geratemp( Tipo tipo );
string geraLabel( string nome );
Tipo buscaTipoVar( string nome );
void insereVar( string nome, Tipo tipo );
void insereVarLocal( string nome, Tipo tipo );
void erroSemantico( string msg );
string geraTemporarias();

void insereFuncao( string nome, Tipo tipo );
void insereParametroFuncao( string nomeFuncao, string nomeParametro, Tipo tipoParametro );
string tipoRetorno( const Tipo& tipo );
void zeraTabelaLocal();
string declaraResult();
bool verificaFuncaoExiste(string nomeFuncao);

// Funções de conversão
int toInt( string n );
void trocaAspasSimples( string& str );

map<string, Funcao> tf;
string funcaoAtual;

%}

%token _ID _OPEN _CLOSE _C_INT _C_STRING _C_DOUBLE _C_CHAR
%token _FUNCTION _VAR _IF _THEN _ELSE _ATRIB
%token _DIF _GEQ _LEQ _OR _AND _NOT
%token _FOR _DO _WHILE  
%token _INTEGER _DOUBLE _CHAR _STRING _BOOL
%token _PROG_MAIN _MAIN _ARRAY _OF
%token _PRINT _PRINTLN _READ

%left _OR
%left _AND
%nonassoc '<' '>' '=' _DIF _GEQ _LEQ
%left '+' '-'
%left '*' '/' '%'

%%

S: DECLS BLOCO_PRINCIPAL  { cout << "#include <stdlib.h>" << endl
          << "#include <string.h>" << endl
          << "#include <iostream>" << endl 
          << endl
          << "using namespace std;" << endl
          << endl
          << $1.c 
          << $2.c << endl; }
 ;

DECLS: DECLVARS DECLS { $$.c = $1.c + $2.c; }
     | FUNCT DECLS { $$.c = $1.c + $2.c; }
     | { $$.c = ""; }
     ;


IDFUNC: _FUNCTION TYPE _ID
      {
        insereFuncao($3.v, $2.t);
        funcaoAtual = $3.v;

        insereVarLocal("result", $2.t);

        $$.t = $2.t;
        $$.v = $3.v;
      }

CABPARAMFUNC: IDFUNC '(' PARAMS ')'
            {
              $$.c = tipoRetorno($1.t) + " " + $1.v + "(" + $3.c + ")";
                     "}\n\n";
            }

FUNCT: CABPARAMFUNC CORPOFUN
     { 
       zeraTabelaLocal();
       $$.c = $1.c + " {\n" +
              declaraResult() +
              $2.c +
              "return result;\n" +
              "}\n\n";
     }
     ;

CORPOFUN : _OPEN DECLVARSLOCAL CMDS _CLOSE
         {
           $$.c = $2.c +
                  geraTemporarias() + "\n" + 
                  $3.c;
         }
         ;

PARAMS: PARAM ';' PARAMS
      {
        $$.c = $1.c + ", " + $3.c;
      }
      | PARAM
      ;

PARAM: _ID ':' TYPE
     {
       insereParametroFuncao(funcaoAtual, $1.v, $3.t);
       $$.t = $3.t;
       $1.t = $3.t;
       $$.c = toString( $1.v, $3.t );
     }
     
DECLVARS: _VAR VARS { $$.c = $2.c; }
        ; 

VARS: VAR ';' _VAR VARS { $$.c = $1.c + $4.c; }
    | VAR ';' { $$.c = $1.c + "\n"; }
    ;

VAR: _ID ':' TYPEVAR
   {
     insereVar( $1.v, $3.t );
     $$.t = $3.t;
     $$.c = toString( $1.v, $3.t ) + ";\n";
   } 
   | _ID ',' VAR
   {
     insereVar( $1.v, $3.t );
     $$.t = $3.t;
     $$.c = toString( $1.v, $3.t ) + ";\n" + $3.c;
   }

DECLVARSLOCAL: _VAR VARSLOCAL { $$.c = $2.c; }
             | { $$.c = ""; }
             ; 

VARSLOCAL: VARLOCAL ';' _VAR VARSLOCAL { $$.c = $1.c + $4.c; }
         | VARLOCAL ';' { $$.c = $1.c + "\n"; }
         ;

VARLOCAL: _ID ':' TYPEVAR
        {
           insereVarLocal( $1.v, $3.t );
           $$.t = $3.t;
           $$.c = toString( $1.v, $3.t ) + ";\n";
        } 
        | _ID ',' VAR
        {
          insereVarLocal( $1.v, $3.t );
          $$.t = $3.t;
          $$.c = toString( $1.v, $3.t ) + ";\n" + $3.c;
        }

TYPEVAR : TYPE
         | _ARRAY '[' _C_INT ']' _OF TYPE
         { $$.t = Tipo( $6.t.base, toInt( $3.v ) ); }  
         | _ARRAY '[' _C_INT ',' _C_INT ']' _OF TYPE
         { $$.t = Tipo( $8.t.base, toInt( $3.v ), toInt( $5.v ) ); }  
        ;

TYPE: _INTEGER
    | _DOUBLE 
    | _CHAR
    | _STRING
    | _BOOL
    ;

BLOCK: _OPEN CMDS _CLOSE { $$.c = $2.c + $3.c; }  //aqui
     ;

BLOCO_PRINCIPAL: _PROG_MAIN CORPOFUN '.'
               {
                 funcaoAtual = "**main**";
                 zeraTabelaLocal();
                 $$.c = "int main() {\n" +
                        $2.c +
                        "return 0;\n" +
                        "}\n";
               } 
               | _MAIN BLOCK '.'
               {
                 funcaoAtual = "**main**";
                 zeraTabelaLocal();
                 $$.c = "int main() {\n" +
                        $2.c +
                        "return 0;\n" +
                        "}\n";
               } 
               ;

CMDS : CMD CMDS { $$.c = $1.c + $2.c; }
     |{ $$.c = ""; }
     ;

CMD: CMD_IF
   | CMD_ATRIB  
   | CMD_FOR
   | CMD_WHILE 
   | CMD_PRINT
   | CMD_READ
   | CMD_FUNC
   ;

CMD_FUNC:  _ID '(' ARGS ')' ';'
        {
          $$.c = $1.v + "( " + $3.v + " )" + ";\n";  
        }

CMD_PRINT: _PRINTLN '(' LEIMP ')' ';'
         {
           $$.c = $3.c + 
                  "cout << endl;\n"; 
         }
         | _PRINT '(' LEIMP ')' ';'
         {
           $$.c = $3.c;
         }

CMD_READ: _READ '(' _ID ')' ';'
        {
          $$.c = "cin >> " + $3.v + ";\n";
        }

LEIMP : LEIMP ',' E
      { 
        $$.c = $1.c + $3.c + 
               "cout << " + $3.v + ";\n" ;
      }
      | E  
      {
        $$.c = $1.c + 
               "cout << " + $1.v + ";\n";
      }

CMD_IF: _IF '(' E ')' BLOCK
    {
	    $$.v = "";
	    $$.t = Tipo();
	    string lbl_then = geraLabel( "then" ), lbl_fim = geraLabel( "endif" );

	    $$.c = $3.c +
	           "if ( !" + $3.v + " ) goto " + lbl_fim + ";\n" +
             $5.c + 
             lbl_fim +":\n";
	  }
	  | _IF '(' E ')' BLOCK _ELSE BLOCK
	  {
          $$.v = "";
          $$.t = Tipo();
          string lbl_then = geraLabel( "then" ),
                 lbl_fim = geraLabel( "endif" ); 
          $$.c = $3.c + 
               "if( " + $3.v + " ) goto " + lbl_then + ";\n" +
               $7.c + // Else
               "goto " + lbl_fim + ";\n" +
               lbl_then + ":\n" +
               $5.c +
               lbl_fim + ":\n";
    }
    ;

CMD_FOR : _FOR '(' CMD_ATRIB  E ';' CMD_ATRIB ')' BLOCK
        {
          string lbl_cond_for = geraLabel("cond_for");

          $$.c = $3.c +
                 lbl_cond_for + ": \n" +
                 $8.c +
                 $6.c +
                 $4.c +
                 "if ( " + $4.v + " ) goto " + lbl_cond_for + ";\n";
        }
        ;

CMD_WHILE : _WHILE '(' E ')' BLOCK
          {
            string lbl_cond_while = geraLabel("cond_while"),
                   lbl_end_while = geraLabel("end_while");

            $$.c = lbl_cond_while + ": \n" + 
                   $3.c +
                   "if (! " + $3.v + " ) goto " + lbl_end_while + ";\n" +
                   $5.c +
                   "goto " + lbl_cond_while + ";\n" +
                   lbl_end_while + ": \n";
          }
          ; 

CMD_ATRIB : _ID _ATRIB E ';'
            { $1.t = buscaTipoVar( $1.v );
              geraAtribuicao( $$, $1, $3 ); }
          | _ID '[' E ']' _ATRIB E ';'
            { $1.t = buscaTipoVar( $1.v );
              geraAtribuicaoArray1( $$, $1, $3, $6 ); }
          | _ID '[' E ',' E ']' _ATRIB E ';'
            { $1.t = buscaTipoVar( $1.v );
              geraAtribuicaoArray2( $$, $1, $3, $5, $8 ); }
          | _ID '[' E ']' '[' E ']' _ATRIB E ';'
            { $1.t = buscaTipoVar( $1.v );
              geraAtribuicaoArray2( $$, $1, $3, $6, $9 ); }
          ;

E : E _OR E     { geraCodigoOperador( $$, "||", $1, $3 ); }
  | E _AND E    { geraCodigoOperador( $$, "&&", $1, $3 ); }
  | E '<' E     { geraCodigoOperador( $$, "<", $1, $3 ); }
  | E '>' E     { geraCodigoOperador( $$, ">", $1, $3 ); }
  | E '=' E     { geraCodigoOperador( $$, "==", $1, $3 ); }
  | E _DIF E    { geraCodigoOperador( $$, "!=", $1, $3 ); }
  | E _GEQ E    { geraCodigoOperador( $$, ">=", $1, $3 ); }
  | E _LEQ E    { geraCodigoOperador( $$, "<=", $1, $3 ); }
  | E '-' E     { geraCodigoOperador( $$, "-", $1, $3 ); }
  | E '*' E     { geraCodigoOperador( $$, "*", $1, $3 ); }
  | E '/' E     { geraCodigoOperador( $$, "/", $1, $3 ); }
  | E '%' E     { geraCodigoOperador( $$, "%", $1, $3 ); }
  | E '+' E     { geraCodigoOperador( $$, "+", $1, $3 ); }
  | F
  ;

F : _ID       { $$.v = $1.v; 
                $$.c = $1.c; 
                $$.t = buscaTipoVar( $$.v ); }
  | _C_INT
  | _C_DOUBLE
  | _C_STRING { trocaAspasSimples($1.v); $$.v = $1.v; }
  | _C_CHAR
  | '(' E ')' { $$ = $2; } 
  | _NOT F
  | '-' F
  | '+' F
  | _ID '(' ARGS ')'
    { 
      if (!verificaFuncaoExiste($1.v)) erroSemantico("Funcao nao declarada: " + $1.v);
      else {
        $$.t = tf[$1.v].retorno; 
        $$.v = geratemp( $$.t ); // Falta testar se a funcao existe!!!
        $$.c = $3.c + 
               $$.v + " = " + $1.v + "( " + $3.v + " );\n";
      }
    }
  | _ID '[' E ']'
    { geraCodigoArray1( $$, $1, $3 ); }       
  | _ID '[' E ',' E ']'
    { geraCodigoArray2( $$, $1, $3, $5 ); }       
  | _ID '[' E ']' '[' E ']'
    { geraCodigoArray2( $$, $1, $3, $6 ); } 
  ;
  
ARGS : E ',' ARGS {$$.c = $1.c + $3.c; $$.v = $1.v + " , "+$3.v;}
     | E          {$$.c = $1.c; $$.v = $1.v;}
     ;


%%

int numLinha = 1;
int numCol = 0;
string ultimoToken = "";
string ultimaLinha = "";

void rastreiaToken( const char* lexema, 
                    const char* tipo = "" );

void trocaAspasSimples( string& str ) {
  if (str[0] == '\'')
    str[0] = '\"';
  if (str[str.size()-1] == '\'')
    str[str.size()-1] = '\"';
}

void panico( int linha, string msg ) {
  cout << "Panico linha " << linha << endl
       << msg << endl;
  exit(0);
}

#include "lex.yy.c"

void rastreiaToken( const char* lexema, 
                    const char* tipo ) {
  yylval.c = "";
  yylval.v = yytext;
  yylval.t = Tipo( tipo );

  numCol += strlen(yytext);  
  ultimoToken = yytext;
  ultimaLinha += ultimoToken;
}

void yyerror( const char* st )
{
  cout << st << endl;
  cout << "Linha       : " << numLinha << endl;
  cout << "Coluna      : " << numCol << endl;
  cout << "Ultimo Token: " << ultimoToken << endl;
  cout << "Ultima Linha: " << ultimaLinha << endl;
}

void erroSemantico( string msg ) {
  cout << msg << endl;
  cout << "Linha       : " << numLinha << endl;
  cout << "Coluna      : " << numCol << endl;
  cout << "Ultimo Token: " << ultimoToken << endl;
  cout << "Ultima Linha: " << ultimaLinha << endl;
  exit(0);
}

struct NumTemp {
  int Int, Char, Bool, String, Double;
} numTemp = { 0, 0, 0, 0, 0 };

string toString( int n ) {
  char buf[200];
  
  sprintf( buf, "%d", n );

  return buf;
}

string geraTemporaria( string const tipo,
                       const char* letraTipo,
                       int& num, 
                       string array = "" ) {
  string aux = "";
  char buf[200];

  for( int i = 0; i < num; i++ ) {
    sprintf( buf, "t%s_%03d", letraTipo, i );
    aux += tipo + " " + buf + array + ";\n";
  }

  num = 0; // como eh passado por referencia, zera o numero de temporarias ja "alocadas"
  return aux;
}

string geraTemporarias() {
  return geraTemporaria( "int", "i", numTemp.Int, "" ) +
    geraTemporaria( "char", "c", numTemp.Char, "" ) +
    geraTemporaria( "double", "d", numTemp.Double, "" ) +
    geraTemporaria( "int", "b", numTemp.Bool, "" ) +
    geraTemporaria( "char", "s", numTemp.String, "[256]" );
}

string geraLabel( string nome ) {
  static int numLabel = 0;

  return "lbl_" + nome + "_" + toString( ++numLabel );
}

string geratemp( Tipo tipo ) {
  char buf[200];
  
  if( tipo.dim1 > 0 || tipo.dim2 > 0 )
    erroSemantico( "Vetores nao podem ser usados em operações" );

  if( tipo.base == "i" ) 
    sprintf( buf, "ti_%03d", numTemp.Int++ );
  else if( tipo.base == "d" ) 
    sprintf( buf, "td_%03d", numTemp.Double++ );
  else if( tipo.base == "c" ) 
    sprintf( buf, "tc_%03d", numTemp.Char++ );
  else if( tipo.base == "b" ) 
    sprintf( buf, "tb_%03d", numTemp.Bool++ );
  else if( tipo.base == "s" ) 
    sprintf( buf, "ts_%03d", numTemp.String++ );
  else
    panico( __LINE__, "BUG!!! Tipo nao definido" + tipo.base);

  return buf;
}

string dimensoes( int dim1, int dim2 ) {
  string aux = "";
  
  if( dim1 > 0 && dim2 == 0 ) 
    aux += "[" + toString( dim1 ) + "]";

  else if( dim1 > 0 && dim2 > 0 )
      aux += "[" + toString( dim1*dim2 ) + "]";

  return aux;
}

string toString( const string& nome, const Tipo& t ) {
  string aux = "";

  if( t.base == "i" )
    return "int " + nome + dimensoes( t.dim1, t.dim2 );
  else if( t.base == "c" )
    return "char " + nome + dimensoes( t.dim1, t.dim2 );
  else if( t.base == "d" )
    return "double " + nome + dimensoes( t.dim1, t.dim2 );
  else if( t.base == "b" )
    return "int " + nome + dimensoes( t.dim1, t.dim2 );
  else if( t.base == "s" )
    return "char " + nome + dimensoes( 256*(t.dim1>0?t.dim1:1), t.dim2 );
  else
    panico( __LINE__, "BUG!!! Tipo nao definido " + t.base );

  return "void*";
}

string tipoRetorno( const Tipo& t ) {
  string aux = "";

  if( t.base == "i" ) return "int";
  else if( t.base == "c" ) return "char";
  else if( t.base == "d" ) return "double";
  else if( t.base == "b" ) return "int";
  else if( t.base == "s" )
    panico( __LINE__, "Impossivel retornar strings");
  else
    panico( __LINE__, "BUG!!! Tipo nao definido " + t.base );

  return "void*";
}

map<string, string> tabTipoResultado;

string tipoResultado( string opr, 
                      Tipo tipoA, 
                      Tipo tipoB ) {
  string tr = tabTipoResultado[tipoA.base + opr + tipoB.base];

  if( tr == "" )
    erroSemantico( "O operador " + opr + 
                   " nao esta definido para " + tipoA.base + 
                   " e " + tipoB.base );

  return tr;
}

void geraCodigoOperador( Atributos& ss,
                         string opr,
                         const Atributos& s1,
                         const Atributos& s3 ) {

  ss.t = tipoResultado( opr, s1.t, s3.t ); 
  ss.v = geratemp(ss.t);
  ss.c = s1.c + s3.c +
         ss.v + " = " + s1.v + " " + opr + " " + s3.v + ";\n";
}

void inicializaTabTipoResultado() {
  // Operador +
  tabTipoResultado["i+i"] = "i";
  tabTipoResultado["i+d"] = "d";
  tabTipoResultado["d+i"] = "d";
  tabTipoResultado["d+d"] = "d";

  tabTipoResultado["c+c"] = "s";
  tabTipoResultado["c+s"] = "s";
  tabTipoResultado["s+c"] = "s";
  tabTipoResultado["s+s"] = "s";

  // Operador -
  tabTipoResultado["i-i"] = "i";
  tabTipoResultado["i-d"] = "d";
  tabTipoResultado["d-i"] = "d";
  tabTipoResultado["d-d"] = "d";

  // Operador *
  tabTipoResultado["i*i"] = "i";
  tabTipoResultado["i*d"] = "d";
  tabTipoResultado["d*i"] = "d";
  tabTipoResultado["d*d"] = "d";

  // Operador /
  tabTipoResultado["i/i"] = "i";
  tabTipoResultado["i/d"] = "d";
  tabTipoResultado["d/i"] = "d";
  tabTipoResultado["d/d"] = "d";

  // Operador %
  tabTipoResultado["i%i"] = "i";

  // Operador <
  tabTipoResultado["i<i"] = "b";
  tabTipoResultado["i<d"] = "b";
  tabTipoResultado["d<i"] = "b";
  tabTipoResultado["d<d"] = "b";
  tabTipoResultado["b<b"] = "b";
  tabTipoResultado["c<s"] = "b";
  tabTipoResultado["s<c"] = "b";
  tabTipoResultado["s<s"] = "b";
  tabTipoResultado["b<b"] = "b";

  // Operador >
  tabTipoResultado["i>i"] = "b";
  tabTipoResultado["i>d"] = "b";
  tabTipoResultado["d>i"] = "b";
  tabTipoResultado["d>d"] = "b";
  tabTipoResultado["b>b"] = "b";
  tabTipoResultado["c>s"] = "b";
  tabTipoResultado["s>c"] = "b";
  tabTipoResultado["s>s"] = "b";
  tabTipoResultado["b>b"] = "b";

  // Operador <=
  tabTipoResultado["i<=i"] = "b";
  tabTipoResultado["i<=d"] = "b";
  tabTipoResultado["d<=i"] = "b";
  tabTipoResultado["d<=d"] = "b";
  tabTipoResultado["b<=b"] = "b";
  tabTipoResultado["c<=s"] = "b";
  tabTipoResultado["s<=c"] = "b";
  tabTipoResultado["s<=s"] = "b";
  tabTipoResultado["b<=b"] = "b";

  // Operador >=
  tabTipoResultado["i>=i"] = "b";
  tabTipoResultado["i>=d"] = "b";
  tabTipoResultado["d>=i"] = "b";
  tabTipoResultado["d>=d"] = "b";
  tabTipoResultado["b>=b"] = "b";
  tabTipoResultado["c>=s"] = "b";
  tabTipoResultado["s>=c"] = "b";
  tabTipoResultado["s>=s"] = "b";
  tabTipoResultado["b>=b"] = "b";

  // Operador 'and' 'or' 'not'
  tabTipoResultado["b&&b"] = "b";
  tabTipoResultado["b||b"] = "b";
  tabTipoResultado["b!=b"] = "b";
}

map<string, Tipo> tsg;
map<string, Tipo> tsl;

Tipo buscarParametroFuncao(string nome) {
  if (tf.find(funcaoAtual) == tf.end()) return Tipo("");
  
  Funcao func = tf[funcaoAtual];
  vector<string> nomes = func.nomeParams;
  
  int i;
  for (i = 0; i < nomes.size(); i++) {
    if (nomes[i] == nome) {
      return func.params[i];
    }
  }

  return Tipo("");
}

Tipo buscaTipoVar( string nome ) {
  if( tsl.find( nome ) == tsl.end() ) {
    
    // Procurando variavel que seja parametro da funcao
    Tipo t = buscarParametroFuncao(nome);
    if (!t.base.empty()) {
      return t;
    }

    if( tsg.find( nome ) == tsg.end() ) {
      erroSemantico( "Variavel nao declarada: " + nome );  

      return Tipo("");
    }
    else {
      return tsg[nome]; 
    }
  } else {
    return tsl[nome];  
  }
}

void insereVar( string nome, Tipo tipo ) {
  if( tsg.find( nome ) != tsg.end() )
    erroSemantico( "Variavel ja declarada: " + nome );  

  tsg[nome] = tipo;
}

void insereVarLocal( string nome, Tipo tipo ) {
  if( tsl.find( nome ) != tsl.end() )
    erroSemantico( "Variavel ja declarada: " + nome );  

  tsl[nome] = tipo;
}

void zeraTabelaLocal() {
  tsl.clear();
}

void insereFuncao( string nome, Tipo tipo ) {
  if( verificaFuncaoExiste(nome) ) {
    erroSemantico( "Função já declarada: " + nome );
  }
  
  tf[nome].retorno = tipo;
}

void insereParametroFuncao( string nomeFuncao, string nomeParametro, Tipo tipoParametro ) {
  tf[nomeFuncao].params.push_back(tipoParametro);
  tf[nomeFuncao].nomeParams.push_back(nomeParametro);
}

string declaraResult() {
  return tipoRetorno( tf[funcaoAtual].retorno ) + " result;\n";
}

bool verificaFuncaoExiste(string nomeFuncao) {
  return tf.find( nomeFuncao ) != tf.end();
}

int toInt( string n ) {
  int aux = 0;
  
  if( sscanf( n.c_str(), "%d", &aux ) != 1 )
    panico( __LINE__, "BUG!!! Nao conseguiu converter " + n );

  return aux;
}

void geraCodigoArray1( Atributos& ss, 
                       const Atributos& s1,
                       const Atributos& s3 ) { 
  Tipo t = buscaTipoVar(s1.v);

  if( t.dim1 == 0 )
     erroSemantico( "A variavel nao é array: " + s1.v );

  if( t.dim2 != 0 )
     erroSemantico( "Array bidimensional usado como unidimensional: " + s1.v );
  
  if( s3.t.base != "i" || s3.t.dim1 != 0 )
     erroSemantico( "O indice do array deve ser inteiro :" + s3.v );

  ss.t = Tipo( t.base );
  ss.v = geratemp(ss.t); 
  ss.c = s3.c +
         ss.v + " = " + s1.v + "[" + s3.v + "];\n"; 
}

void geraCodigoArray2( Atributos& ss, 
                       const Atributos& s1,
                       const Atributos& s3,
                       const Atributos& s5 ) { 
  Tipo t = buscaTipoVar(s1.v);

  if( t.dim1 == 0 )
     erroSemantico( "A variavel nao é array: " + s1.v );

  if( t.dim2 == 0 )
     erroSemantico( "Array unidimensional usado como bidimensional: " + s1.v );
  
  if( s3.t.base != "i" || s3.t.dim1 != 0 )
     erroSemantico( "O primeiro indice do array deve ser inteiro :" + s3.v );

  if( s5.t.base != "i" || s5.t.dim1 != 0 )
     erroSemantico( "O segundo indice do array deve ser inteiro :" + s5.v );

  ss.t = Tipo( t.base );
  ss.v = geratemp(ss.t); 
  string tempIndice = geratemp(s3.t);
  ss.c = s3.c + s5.c +
         tempIndice + " = " + s3.v + " * " + toString( t.dim1 ) + ";\n" + 
         tempIndice + " = " + tempIndice + " + " + s5.v + ";\n" + 
         ss.v + " = " + s1.v + "[" + tempIndice + "];\n"; 
}

void geraAtribuicao( Atributos& ss, 
                     const Atributos& s1,
                     const Atributos& s3  ) {
  if( s1.t.dim1 != 0 || s3.t.dim1 != 0 )
    erroSemantico( "Não é permitida a atribuição de arrays: " + s1.v + " e " + s3.v ); 

  // Tratar conversões especiais
  if( s1.t.base == "d" && s3.t.base == "i" )
    ; // Nada a fazer, pode atribuir
  else
    if( s1.t.base != s3.t.base )
      erroSemantico( "Não é permitida a conversão entre tipos: " + 
                     s1.v + "/" + s1.t.base + " e " + 
                     s3.v + "/" + s3.t.base );

  // Ok, pode prosseguir
  ss.v = "";
  if( s1.t.base == "s" ) 
    ss.c = s3.c + 
           "strncpy( " + s1.v + ", " + s3.v + ", 255 );\n";
  else 
    ss.c = s3.c + 
           s1.v + " = " + s3.v + ";\n";    
}

void geraAtribuicaoArray1( Atributos& ss, 
                           const Atributos& s1,
                           const Atributos& s3,
                           const Atributos& s6 ) {
  if( s1.t.dim1 == 0 || s1.t.dim2 != 0 )
    erroSemantico( "A variável " + s1.v + " não é array unidimensional." );

  if( s3.t.dim1 != 0 || s3.t.base != "i" )
    erroSemantico( "A variável indice não é inteira." );

  if( s6.t.dim1 != 0 )
    erroSemantico( "Não é permitida a atribuição de arrays: " + s6.v );

  // Tratar conversões especiais
  if( s1.t.base == "d" && s6.t.base == "i" )
    ; // Nada a fazer, pode atribuir
  else
    if( s1.t.base != s6.t.base )
      erroSemantico( "Não é permitida a conversão entre tipos: " + 
                     s1.v + "/" + s1.t.base + " e " + 
                     s6.v + "/" + s6.t.base );

  // Ok, pode prosseguir
  ss.v = "";
  if( s1.t.base == "s" ) 
    ss.c = s3.c + s6.c +
           "strncpy( " + s1.v + "["+ s3.v +"], " + s6.v + ", 255 );\n";
  else 
    ss.c = s3.c + s6.c + 
           s1.v + "["+ s3.v +"] = " + s6.v + ";\n";    
}

void geraAtribuicaoArray2( Atributos& ss, 
                           const Atributos& s1,
                           const Atributos& s3,
                           const Atributos& s5,
                           const Atributos& s8 ) {
  if( s1.t.dim1 == 0 || s1.t.dim2 == 0 )
    erroSemantico( "A variável " + s1.v + " não é array bidimensional." );

  if( s3.t.dim1 != 0 || s3.t.base != "i" )
    erroSemantico( "A variável do primeiro indice não é inteira." );

  if( s5.t.dim1 != 0 || s5.t.base != "i" )
    erroSemantico( "A variável do segundo indice não é inteira." );

  if( s8.t.dim1 != 0 )
    erroSemantico( "Não é permitida a atribuição de arrays: " + s8.v );

  // Tratar conversões especiais
  if( s1.t.base == "d" && s8.t.base == "i" )
    ; // Nada a fazer, pode atribuir
  else
    if( s1.t.base != s8.t.base )
      erroSemantico( "Não é permitida a conversão entre tipos: " + 
                     s1.v + "/" + s1.t.base + " e " + 
                     s8.v + "/" + s8.t.base );

  // Ok, pode prosseguir
  ss.v = "";
  string tempIndice = geratemp(s3.t);

  if( s1.t.base == "s" ) 
    ss.c = s3.c + s5.c + s8.c +
           tempIndice + " = " + s3.v + " * " + toString( s1.t.dim1 ) +";\n" +
           tempIndice + " = " + tempIndice + " + " + s5.v +";\n" +
           "strncpy( " + s1.v + "["+ tempIndice +"], " + s8.v + ", 255 );\n";
  else 
    ss.c = s3.c + s5.c + s8.c + 
           tempIndice + " = " + s3.v + " * " + toString( s1.t.dim1 ) +";\n" +
           tempIndice + " = " + tempIndice + " + " + s5.v +";\n" +
           s1.v + "["+ tempIndice +"] = " + s8.v + ";\n";    
}

int main( int argc, char* argv[] )
{
  inicializaTabTipoResultado();
  yyparse();
}




